import Router from 'koa-router'
import { resolve } from 'path'
import _ from 'lodash'
import { glob } from 'glob' //用正则去匹配文件

export let routesMap = new Map()
export const symbolPrefix = Symbol('prefix')
export const normalizePath = path => path.startsWith('/') ? path : `/${path}`
export const isArray = c => _.isArray(c) ? c : [c]

export default class Route{
    constructor(app,apipath){
        this.app = app
        this.router = new Router()
        this.apipath = apipath
    }
    init(){
        /**
         * 这里利用传进来的apipath去引入后缀为js的文件
         */
        glob
          .sync(resolve(this.apipath,'./*.js'))
          .forEach(require);
        
        for(let [ conf , controller ] of routesMap){
            /*
            *思路就是把每一个路由文件的controller拎出来
            * 然后跟它的路由做一个一一匹配
            * */
            const controllers = isArray(controller) 
            let prefixPath = conf.target[symbolPrefix]
            if(prefixPath) prefixPath = normalizePath(prefixPath)

            const routerPath = prefixPath + conf.path
            this.router[conf.method](routerPath,...controllers) //function (name, path, middlewares)
        }
        this.app.use(this.router.routes()) // 添加路由中间件
        this.app.use(this.router.allowedMethods()) // 对请求进行一些限制处理
    }
}

/**
 * 
 * @param {path,target} 
 * 保证每一个controller都是独一无二的 
 */
export const controller = path => target => target.prototype[symbolPrefix] = path

/**
 * 
 * @param {conf} 
 * 定义简单的route 
 */
export const route = conf => (target, key, desc) =>{
    conf.path = normalizePath(conf.path)
    routesMap.set({
        target:target,
        ...conf,
    },target[key])
}

/**
 * 
 * @param {path} 
 * 定义get方法
 */
export const get = path => route({
    method:'get',
    path:path
})

/**
 * 
 * @param {path} 
 * 定义post方法 
 */
export const post = path => route({
    method:'post',
    path:path
})

/**
 * 
 *  打印日志
 */
let reqID = 0

const decorate = (args, middleware) => {
  let [ target, key, descriptor ] = args
  target[key] = isArray(target[key])
  target[key].unshift(middleware)
  return descriptor
}

export const convert = middleware => (...args) => decorate(args, middleware)

export const log = convert(async (ctx, next) => {
    let currentReqID = reqID++
    console.time(`${currentReqID} ${ctx.method} ${ctx.url}`)
    await next()
    console.timeEnd(`${currentReqID} ${ctx.method} ${ctx.url}`)
  })
  